/** Color */
import java.awt.Color;

/** Dimension */
import java.awt.Dimension;

/** Graphics */
import java.awt.Graphics;

/** Serializable */
import java.io.Serializable;

/**
 * HW 12b & 13b, Problem 2, "Piece"<br><br>
 * 
 * This class represents a Piece, for every tetrominoes to be created. 
 * It includes the information about the current x and y (row, column)
 *  information of the current place, the color, and the model. 
 * It also contains some methods for the piece, like rotating and settling. 
 * 
 * @author Hyun Seo Chung
 * @version 1.0 04/21/12
 */
public abstract class Piece implements Serializable {
	
	/**
	 * serialVersionUID for the Piece class
	 */
	private static final long serialVersionUID = 1L;
	
	/**
	 * The x and the y values of the piece
	 */
	private int x, y;
	
	/**
	 * Color of the piece
	 */
	private final Color color;
	
	/**
	 * Multidimensional array representing the current model
	 */
	private int[][] model;
	
	/**
	 * Current PlayingField from the PlayingPanel
	 */
	private final PlayingField field = PlayingPanel.getField();
	
	/**
	 * This is a constructor to set up the piece's
	 *  x and y position, color, and the model. 
	 * 
	 * @param x The current column number of the board where the piece is located
	 * @param y The current row number of the board where the piece is located
	 * @param color The current color of the piece (represents the shape)
	 * @param model The current model of the piece
	 */
	public Piece(int x, int y, Color color, int[][] model) {
		this.x = x;
		this.y = y;
		this.color = color;
		this.model = model.clone();
	}
	
	/**
	 * This method moves the piece to a difference of dx
	 *  and dy from the current x and y position, if possible. 
	 * 
	 * @param dx The difference in x position to be moved
	 * @param dy The difference in y position to be moved
	 * @return true if the piece was able (allowed)
	 *  to move to the position wanted, false otherwise
	 */
	public boolean canMove(int dx, int dy) {
		for ( int i = 0; i < model.length; i++ ) {
			for ( int j = 0; j < model.length; j++ ) {
				if (model[i][j] == 1) {
					if (!field.isTileVacant(x + j + dx, y + i + dy)) {
						return false;
					}
				}
			}
		}
		this.x += dx;
		this.y += dy;
		return true;
	}
	
	/**
	 * This method rotates the piece to the next model, if possible. 
	 * 
	 * @return true if the piece was able (allowed) to rotate, false otherwise
	 */
	public abstract boolean canRotate();
	
	/**
	 * This method settles the piece to the current position, 
	 * filling the corresponding tiles in to the field. 
	 */
	public void settle() {
		for ( int i = 0; i < model.length; i++ ) {
			for ( int j = 0; j < model.length; j++ ) {
				if (model[i][j] == 1) {
					if (this.y + i >= 0) {
						field.fillTile(j + this.x, i + this.y, this.color);
					}
				}
			}
		}
	}
	
	/**
	 * This method draws the piece to the main board,
	 *  apart from the current field (settled pieces). 
	 * 
	 * @param g The Graphics object to be drawn on
	 * @param tileDimension The current tileDimension that the tiles should be drawn with
	 */
	public void draw(Graphics g, Dimension tileDimension) {
		for ( int i = 0; i < model.length; i++ ) {
			for ( int j = 0; j < model.length; j++ ) {
				if (model[i][j] == 1) {
					g.setColor(this.color);
					g.fillRect(this.x * tileDimension.width + j *
							tileDimension.width, this.y * tileDimension.height + i *
							tileDimension.height, tileDimension.width,
							tileDimension.height);
				}
			}
		}
	}
	
	/**
	 * This is a getter for the current x position value of the piece.
	 * 
	 * @return The current x position value of the piece
	 */
	public int getX() {
		return x;
	}

	/**
	 * This is a getter for the current y position value of the piece
	 * 
	 * @return The current y position value of the piece
	 */
	public int getY() {
		return y;
	}

	/**
	 * This is a getter for the current Color of the piece
	 * 
	 * @return The current Color of the piece
	 */
	public Color getColor() {
		return color;
	}
	
	/**
	 * This is a getter for the current model of the piece
	 * 
	 * @return The current model of the piece
	 */
	public int[][] getModel() {
		return model;
	}

	/**
	 * This is a setter for the model of the piece
	 * 
	 * @param model The model of the piece to be set to
	 */
	public void setModel(int[][] model) {
		this.model = model.clone();
	}

}
